#!/usr/bin/env bash

# Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

srcdir=llvm-project-19.1.5.src
workdir=$(realpath $(dirname "$0"))

CMAKE=cmake
if [ ${impure} -eq 1 ]; then
    CMAKE=${pkgs_root}/${host_dep_cmake}-impure/usr/bin/cmake
fi

if [ ${host_toolchain} -eq 1 ]; then
    export LDFLAGS="${LDFLAGS} -Wl,-rpath-link=/usr/lib:/usr/lib64:/lib:/lib64"
fi

if [ -n "${feature_musl}" ]; then
    if [ -n "${feature_ohos}" ]; then
        triple=${arch}-linux-ohos
    else
        triple=${arch}-unknown-linux-musl
    fi
else
    triple=${arch}-unknown-linux-gnu
fi

if [ ! -z "${feature_standalone_clangrt}" ]; then
    ${CMAKE} \
        -S ${srcdir}/compiler-rt\
        -B build \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX=/usr \
        -DCMAKE_C_FLAGS="-nodefaultlibs -nostdlib" \
        -DCMAKE_CXX_FLAGS="-nodefaultlibs -nostdlib" \
        -DCMAKE_C_COMPILER_TARGET=${triple} \
        -DCMAKE_CXX_COMPILER_TARGET=${triple} \
        -DCMAKE_ASM_COMPILER_TARGET=${triple} \
        -DCMAKE_EXE_LINKER_FLAGS="/usr/lib/Scrt1.o /usr/lib/crti.o /usr/lib/crtn.o -lc" \
        -DCMAKE_SHARED_LINKER_FLAGS="/usr/lib/Scrt1.o /usr/lib/crti.o /usr/lib/crtn.o -lc" \
        -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
        -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
        -DCOMPILER_RT_BUILD_GWP_ASAN=OFF \
        -DCOMPILER_RT_BUILD_XRAY=OFF \
        -DCOMPILER_RT_BUILD_MEMPROF=OFF \
        -DCOMPILER_RT_BUILD_ORC=OFF \
        -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
        || exit 1
    make -C build -j ${MAX_JOBS} || exit 1
    exit 0
fi

if [ ! -z "${feature_standalone_llvmrt}" ]; then
    ${CMAKE} \
        -S ${srcdir}/runtimes \
        -B build \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX=/usr \
        -DCMAKE_C_COMPILER_TARGET=${triple} \
        -DCMAKE_CXX_COMPILER_TARGET=${triple} \
        -DCMAKE_ASM_COMPILER_TARGET=${triple} \
        -DCMAKE_C_COMPILER_WORKS=1 \
        -DCMAKE_CXX_COMPILER_WORKS=1 \
        -DLLVM_HOST_TRIPLE=${triple} \
        -DLLVM_DEFAULT_TARGET_TRIPLE=${triple} \
        -DLLVM_ENABLE_RUNTIMES="libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp" \
        -DCLANG_VERSION_MAJOR=19 \
        -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
        -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
        -DCOMPILER_RT_BUILD_GWP_ASAN=OFF \
        -DCOMPILER_RT_BUILD_XRAY=OFF \
        -DCOMPILER_RT_BUILD_MEMPROF=OFF \
        -DCOMPILER_RT_BUILD_ORC=OFF \
        -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
        -DLIBCXX_CXX_ABI=libcxxabi \
        -DLIBCXX_HAS_MUSL_LIBC=ON \
        -DLIBOMP_OMPD_GDB_SUPPORT=OFF \
        || exit 1

    make -C build -j ${MAX_JOBS} unwind || exit 1
    make -C build -j ${MAX_JOBS} install-unwind || exit 1
    make -C build -j ${MAX_JOBS} install-cxx-headers || exit 1
    make -C build -j ${MAX_JOBS} cxx cxxabi || exit 1
    make -C build -j ${MAX_JOBS} install-cxx install-cxxabi || exit 1
    
    # fix cxx headers for openmp
    mkdir -p /host/usr/include/${triple}/c++/v1 || exit 1
    cp -P /usr/include/c++/v1/__config_site /host/usr/include/${triple}/c++/v1/ || exit 1

    make -C build -j ${MAX_JOBS} || exit 1
    exit 0
fi

if [ ! -z "${feature_standalone_flangrt}" ]; then
    HAS_QUADMATHLIB=""
    if [ ! -z "${feature_musl}" ]; then
       HAS_QUADMATHLIB="-DHAS_QUADMATHLIB=0"
    fi

    ${CMAKE} \
        -S ${srcdir}/flang/runtime \
        -B runtime_build \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX=/usr \
        -DCMAKE_C_FLAGS="${HAS_QUADMATHLIB}" \
        -DCMAKE_CXX_FLAGS="${HAS_QUADMATHLIB} -isystem /usr/include/${triple}/c++/v1 -I${workdir}/${srcdir}/flang/runtime" \
        -DCMAKE_C_COMPILER_TARGET=${triple} \
        -DCMAKE_CXX_COMPILER_TARGET=${triple} \
        -DLLVM_ENABLE_LIBCXX=ON \
        || exit 1

    make -C runtime_build -j ${MAX_JOBS} || exit 1
    make -C runtime_build -j ${MAX_JOBS} install || exit 1

    ${CMAKE} \
        -S ${srcdir}/flang/lib/Decimal \
        -B build \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX=/usr \
        -DCMAKE_C_FLAGS="${HAS_QUADMATHLIB}" \
        -DCMAKE_CXX_FLAGS="${HAS_QUADMATHLIB} -isystem /usr/include/${triple}/c++/v1" \
        -DCMAKE_C_COMPILER_TARGET=${triple} \
        -DCMAKE_CXX_COMPILER_TARGET=${triple} \
        -DLLVM_ENABLE_LIBCXX=ON \
        || exit 1

    make -C build -j ${MAX_JOBS} || exit 1
    
    #TODO  other flang libs

    exit 0
fi

extra_args=()
if [ ! -z "${feature_musl}" ]; then
    if [ ${impure} -eq 0 ]; then
        extra_args+=(-DLIBCXX_HAS_MUSL_LIBC=ON)
        extra_args+=(-DCOMPILER_RT_BUILD_GWP_ASAN=OFF) # musl has no libexecinfo
        extra_args+=(-DLIBOMP_OMPD_GDB_SUPPORT=OFF) # TODO: need python lib, 1) add to depends; 2) correct libpython path
    fi
fi

if [ ${impure} -eq 0 ]; then
    # cross compiling args
    extra_args+=(-DCMAKE_SYSTEM_NAME=Linux)
    if [ "${arch}" != "${host_arch}" ]; then
        host_triple=
        case "${CC_FOR_BUILD}" in
            *clang*)
                host_triple=$(${CC_FOR_BUILD} -dumpmachine)
                ;;
            *gcc*)
                host_triple=${host_arch}-unknown-linux-gnu
                ;;
        esac

        extra_args+=(-DLLVM_NATIVE_TOOL_DIR=/host/usr/bin)
        extra_args+=(-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-DLLVM_NATIVE_TOOL_DIR=/host/usr/bin;-DCMAKE_SYSROOT=/host/usr;-DLLVM_DEFAULT_TARGET_TRIPLE=${host_triple}")
        extra_args+=(-DLIBOMP_FORTRAN_MODULES_COMPILER=/host/usr/bin/flang-new)

        extra_args+=(-DCMAKE_C_COMPILER=${CC_FOR_BUILD})
        extra_args+=(-DCMAKE_CXX_COMPILER=${CXX_FOR_BUILD})
        extra_args+=(-DLLVM_HOST_TRIPLE=${triple})
        extra_args+=(-DCMAKE_C_COMPILER_TARGET=${triple})
        extra_args+=(-DCMAKE_CXX_COMPILER_TARGET=${triple})
        extra_args+=(-DCMAKE_ASM_COMPILER_TARGET=${triple})

        if [ -n "${feature_ohos}" ]; then
            # FIXME: see also in clang-cross-wrapper
            extra_args+=(-DCMAKE_SYSROOT=/)

            # FIXME: ohos triple is not normalized, the inconsistent triple will cause runtimes build error
            export NO_NORMALIZE_TRIPLE=1
        fi

        extra_args+=(-DCOMPILER_RT_DEFAULT_TARGET_TRIPLE=${triple})
        
        # disable cross wrappers
        if [ -n "${CC}" ] && [ "${CC}" != "${CC_FOR_BUILD}" ]; then
            export CC=${CC_FOR_BUILD}
        fi
        if [ -n "${CXX}" ] && [ "${CXX}" != "${CXX_FOR_BUILD}" ]; then
            export CXX=${CXX_FOR_BUILD}
        fi
    else
        extra_args+=(-DLLVM_NATIVE_TOOL_DIR=/usr/bin)
        extra_args+=(-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-DLLVM_NATIVE_TOOL_DIR=/usr/bin")
        extra_args+=(-DLIBOMP_FORTRAN_MODULES_COMPILER=/usr/bin/flang-new)
    fi
    
    extra_args+=(-DCOMPILER_RT_USE_BUILTINS_LIBRARY=ON)
fi

${CMAKE} \
    -S ${srcdir}/llvm \
    -B build \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DLLVM_TARGETS_TO_BUILD=all \
    -DLLVM_ENABLE_PROJECTS="bolt;clang;flang;clang-tools-extra;cross-project-tests;libclc;lld;lldb;mlir;polly" \
    -DLLVM_ENABLE_RUNTIMES="libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp" \
    -DLLVM_INSTALL_UTILS=ON \
    -DCLANG_DEFAULT_CXX_STDLIB=libc++ \
    -DCLANG_DEFAULT_RTLIB=compiler-rt \
    -DCLANG_DEFAULT_UNWINDLIB=libunwind \
    -DCLANG_DEFAULT_OPENMP_RUNTIME=libomp \
    -DLIBCXX_CXX_ABI=libcxxabi \
    ${extra_args[@]} \
    || exit 1

make -C build -j ${MAX_JOBS} clang lld opt lldb mlir-libraries || exit 1
make -C build -j 1 flang-new flang-libraries || exit 1
make -C build -j ${MAX_JOBS} compiler-rt cxx cxxabi || exit 1
make -C build -j ${MAX_JOBS} || exit 1
